package com.csw.shuanfa.CodeImprove.GuavaLimit.rateLimiter;

import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author 1
 */
@Slf4j
public class RateLimiterAcquireExecutorServiceTest {
    public static void main(String[] args) {
        //限流器流速：2个请求/秒,匀速限流，500ms一个
        RateLimiter limiter = RateLimiter.create(Math.pow(10, 5));
        //执行任务的线程池
        ExecutorService es = Executors.newFixedThreadPool(1);
        //记录上一次执行时间
        final long[] prev = {System.nanoTime()};
        //测试执行20次
        for (int i = 0; i < Math.pow(10, 7); i++) {
            //限流器限流
            limiter.acquire();
            //JavaSimpleLimiter2.acquire();
            //JavaSimpleLimiter1.acquire();
            //提交任务异步执行
            int finalI = i;
            es.execute(() -> {
                long cur = System.nanoTime();
                //打印时间间隔：毫秒
                //
                log.info((cur - prev[0]) / 1000_000 + "【i】" + finalI);
                prev[0] = cur;
            });
        }

    }
}
/**
 * https://mp.weixin.qq.com/s/SkvrEFCEv3GKmZWRNelSOg
 * Guava 的限流器使用上还是很简单的，那它是如何实现的呢？Guava 采用的是令牌桶算法，其核心是要想通过限流器，
 * 必须拿到令牌。也就是说，只要我们能够限制发放令牌的速率，那么就能控制流速了。令牌桶算法的详细描述如下：
 * <p>
 * 令牌以固定的速率添加到令牌桶中，假设限流的速率是 r/ 秒，则令牌每 1/r 秒会添加一个；
 * 假设令牌桶的容量是 b ，如果令牌桶已满，则新的令牌会被丢弃；
 * 请求能够通过限流器的前提是令牌桶中有令牌。
 * 这个算法中，限流的速率 r 还是比较容易理解的，但令牌桶的容量 b 该怎么理解呢？b 其实是 burst 的简写，
 * 意义是限流器允许的最大突发流量。比如 b=10，而且令牌桶中的令牌已满，此时限流器允许 10 个请求同时通过限流器，
 * 当然只是突发流量而已，这 10 个请求会带走 10 个令牌，所以后续的流量只能按照速率 r 通过限流器。
 */
